package gao.xiaolei.util;

import java.io.File;
import java.io.IOException;

import org.eclipse.jgit.api.CommitCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.TransportConfigCallback;
import org.eclipse.jgit.api.errors.AbortedByHookException;
import org.eclipse.jgit.api.errors.CanceledException;
import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidConfigurationException;
import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.api.errors.NoFilepatternException;
import org.eclipse.jgit.api.errors.NoHeadException;
import org.eclipse.jgit.api.errors.NoMessageException;
import org.eclipse.jgit.api.errors.RefNotAdvertisedException;
import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.api.errors.TransportException;
import org.eclipse.jgit.api.errors.UnmergedPathsException;
import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.transport.JschConfigSessionFactory;
import org.eclipse.jgit.transport.OpenSshConfig;
import org.eclipse.jgit.transport.SshSessionFactory;
import org.eclipse.jgit.transport.SshTransport;
import org.eclipse.jgit.transport.Transport;
import org.eclipse.jgit.transport.TransportHttp;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import com.jcraft.jsch.Session;

@Component("Jgit")
@RefreshScope
public class Jgit implements InitializingBean {

    @Value("${gitConfig.remoteUrl}")
    private String remoteUrl;//远程仓库的地址

    @Value("${gitConfig.userName}")
    private String userName;//登陆远程仓库的用户名

    @Value("${gitConfig.password}")
    private String password;//登陆远程仓库的密码

    @Value("${gitConfig.remotePath}")
    private String remotePath;//远程仓库的仓库名字

    @Value("${gitConfig.localPath}")
    private String localPath;//要将远程仓库克隆到本地的哪个路径


    //用于解决HostKey问题
    private TransportConfigCallback getTransportConfigCallback() {
        final SshSessionFactory sshSessionFactory = new JschConfigSessionFactory() {
            @Override
            protected void configure(OpenSshConfig.Host host, Session session) {
                session.setConfig("StrictHostKeyChecking", "no");
            }
        };
        return new TransportConfigCallback() {

            public void configure(Transport transport) {
                if (transport instanceof TransportHttp)
                    return;
                SshTransport sshTransport = (SshTransport) transport;
                sshTransport.setSshSessionFactory(sshSessionFactory);
            }
        };
    }

    /**
     * 用于Git-add文件到缓冲区
     *
     * @throws IOException
     * @throws GitAPIException
     * @throws NoFilepatternException
     */
    public void add(String gitName, String fileName) throws NoFilepatternException, GitAPIException, IOException {
        System.out.println("add----begin");
        Git git = Git.open(new File(localPath + "/" + gitName + "/" + ".git"));
        git.add().addFilepattern(fileName).call(); // 相当与git add -A添加所有的变更文件git.add().addFilepattern("*.java")这种形式是不支持的
        // git.add().addFilepattern("src/main/java/").call(); // 添加目录，可以把目录下的文件都添加到暂存区
        // jgit当前还不支持模式匹配的方式，例如*.java
        System.out.println("add----end");
    }

    /**
     * 用于Git-commit文件到区
     *
     * @throws IOException
     * @throws GitAPIException
     * @throws AbortedByHookException
     * @throws WrongRepositoryStateException
     * @throws ConcurrentRefUpdateException
     * @throws UnmergedPathsException
     * @throws NoMessageException
     * @throws NoHeadException
     */
    public void commit(String gitName, String massage)
            throws IOException, NoHeadException, NoMessageException, UnmergedPathsException,
            ConcurrentRefUpdateException, WrongRepositoryStateException, AbortedByHookException, GitAPIException {
        System.out.println("commit----begin");
        Git git = Git.open(new File(localPath + "/" + gitName + "/" + ".git"));
        CommitCommand commitCommand = git.commit().setMessage(massage).setAllowEmpty(true);
        commitCommand.call();
        System.out.println("commit----end");
    }

    /**
     * 把远程仓库clone到指定目录(相当于git clone )
     *
     * @throws TransportException
     * @throws InvalidRemoteException
     * @throws IOException
     * @throws GitAPIException
     */
    public int clone(String remoteName, String gitName)
            throws InvalidRemoteException, TransportException, GitAPIException {
        System.out.println("clone----begin");
        File filePath = new File(localPath + "/" + gitName);
        if (filePath.exists())// 判断要创建的仓库名是否与已有仓库重名
            return 0;
        else {
            String url = userName + "@" + remoteUrl + ":/" + remotePath + "/" + remoteName + ".git";
            Git.cloneRepository().setCloneAllBranches(true).setURI(url).setDirectory(filePath)
                    .setCredentialsProvider(new UsernamePasswordCredentialsProvider(userName, password))
                    .setTransportConfigCallback(getTransportConfigCallback()).call();
            System.out.println("clone----end");
            return 1;
        }

    }

    /**
     * 向远程仓库某个分支push((相当于git push)) 或者用于新建分支向远程仓库的推送
     *
     * @throws GitAPIException
     * @throws TransportException
     * @throws InvalidRemoteException
     * @throws IOException
     */
    public void push(String gitName, String bName, String remoteName)
            throws InvalidRemoteException, TransportException, GitAPIException, IOException {
        System.out.println("push----begin");
        String url = userName + "@" + remoteUrl + ":/" + remotePath + "/" + remoteName + ".git";
        Git git = Git.open(new File(localPath + "/" + gitName + "/" + ".git"));
        Ref ref = git.branchList().setContains(bName).call().get(0);
        git.push().add(ref).setCredentialsProvider(new UsernamePasswordCredentialsProvider(userName, password))
                .setRemote(url).setTransportConfigCallback(getTransportConfigCallback()).call();
        git.close();
        System.out.println("push----end");
    }

    /**
     * 从远程仓库拉取特定分支((相当于git pull))
     *
     * @throws GitAPIException
     * @throws TransportException
     * @throws NoHeadException
     * @throws RefNotAdvertisedException
     * @throws RefNotFoundException
     * @throws CanceledException
     * @throws InvalidRemoteException
     * @throws InvalidConfigurationException
     * @throws WrongRepositoryStateException
     * @throws IOException
     */
    public void pull(String gitName, String bName, String remoteName) throws WrongRepositoryStateException,
            InvalidConfigurationException, InvalidRemoteException, CanceledException, RefNotFoundException,
            RefNotAdvertisedException, NoHeadException, TransportException, GitAPIException, IOException {
        // String url = userName + "@" + remoteUrl + ":/" + remotePath + "/" +
        // remoteName + ".git";
        System.out.println("pull----begin");
        Git git = Git.open(new File(localPath + "/" + gitName + "/" + ".git"));
        git.pull().setRemoteBranchName(bName)
                .setCredentialsProvider(new UsernamePasswordCredentialsProvider(userName, password))
                .setTransportConfigCallback(getTransportConfigCallback()).call();
        git.close();
        System.out.println("pull----end");
    }

    /**
     * 判断本地是否有这个git仓库
     */
    public boolean isHave(String gitName) {
        System.out.println("isHave----begin");
        File f = new File(localPath + "/" + gitName);
        if (f.exists()) {
            System.out.println("isHave----end");
            return true;
        }
        return false;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        File filePath = new File(localPath);
        if (!filePath.exists()) {
            // 如果文件夹不存在
            filePath.mkdir();// 创建文件夹
        }
    }
}
